#ifndef _EVPAXOS_H_
#define _EVPAXOS_H_

#include <iostream>
#include <atomic>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

struct client_value {
    int client_id;
    struct timeval t;
    size_t size;
    char value[1];
};

struct address {
    char *addr;
    int port;
};

struct evpaxos_config {
    int proposers_count;
    int acceptors_count;
    struct address proposers[20];
    struct address acceptors[20];
};


enum option_type {
    option_boolean,
    option_integer,
    option_string,
    option_verbosity,
    option_backend,
    option_bytes
};

struct option {
    const char *name;
    void *value;
    enum option_type type;
};

typedef void (*deliver_function)(
        unsigned int,
        char *value,
        size_t size,
        void *arg);

#ifdef __cplusplus
}
#endif


struct role {
    virtual void set_masterid(int _id) = 0;

    virtual void set_lease_timep(int timep) = 0;

    virtual int get_lease_timep() = 0;

    virtual int get_masterid() = 0;

    virtual bool is_master(int _id) = 0;

    virtual void event_master_change() = 0;

    static std::atomic_int master_id;

    static std::atomic_int lease_timep;

    static int id;

    static struct evpaxos_config *config;
};


struct evlearner *evlearner_init(const char *configf,
                                 deliver_function f,
                                 void *arg,
                                 struct event_base *base,
                                 struct evpaxos_config *config);

void evlearner_free(struct evlearner *l);

struct evacceptor *evacceptor_init(int id,
                                   const char *configf,
                                   struct event_base *b,
                                   struct evpaxos_config *config);

void evacceptor_free(struct evacceptor *a);

struct evproposer *evproposer_init(int id,
                                   role *re,
                                   struct event_base *b,
                                   struct evpaxos_config *config);

void evproposer_free(struct evproposer *p);

struct sockaddr_in evpaxos_proposer_address(struct evpaxos_config *c, int i);

int evpaxos_acceptor_count(struct evpaxos_config *config);

struct evpaxos_config *evpaxos_config_read(const char *path);

void evpaxos_config_free(struct evpaxos_config *config);

int evpaxos_proposer_listen_port(struct evpaxos_config *c, int i);

struct sockaddr_in evpaxos_acceptor_address(struct evpaxos_config *c, int i);

int evpaxos_acceptor_listen_port(struct evpaxos_config *c, int i);


#endif
